#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <aura.h>
#include <aura_wchar.h>

#include "module.h"
#include "peimage.h"

EXTERN_C Aura_PWChar __cdecl Aura_wcsrchr(const Aura_PWChar str, Aura_WChar c);


int g_iDbgFlag_fd;

#define CH_PATH_SEPARATOR '/'

struct DbgData{
    Aura_PWChar m_pwszName;
    long     m_lTextAdd;
    long     m_lDataAdd;
    long     m_lBssAdd;
};

static void GetDbgData(CModule * pModule, DbgData *pDbgData)
{
    unsigned int i;
    Section *pSections;

    pDbgData->m_pwszName
        = Aura_wcsrchr(pModule->m_wszFullPath, CH_PATH_SEPARATOR) + 1;

    pDbgData->m_lTextAdd = 0;
    pDbgData->m_lDataAdd = 0;
    pDbgData->m_lBssAdd  = 0;

    for(i = 0; i < pModule->m_cSections; i++){
        pSections = &pModule->m_pSections[i];
        if(0 == strcmp(".text", pSections->m_szName)){
            pDbgData->m_lTextAdd  = (long)(pModule->m_uImageBase
                + pSections->m_uVAddr);
        }
        if(0 == strcmp(".data", pSections->m_szName)){
            pDbgData->m_lDataAdd = (long)(pModule->m_uImageBase
                + pSections->m_uVAddr);
        }
        if(0 == strcmp(".bss", pSections->m_szName)){
            pDbgData->m_lBssAdd = (long)(pModule->m_uImageBase
                + pSections->m_uVAddr);
        }
        if((0 != pDbgData->m_lTextAdd)
         &&(0 != pDbgData->m_lDataAdd)
         &&(0 != pDbgData->m_lBssAdd)){
            break;
        }
    }
}

static void SetDbgInfo(char *pDbgInfo, DbgData *pDbgData)
{
    int slen;
    //TODO about mutibyte
    Aura_Char ctmp[AURA_MAX_PATH];
    UnicToAnsi(ctmp, pDbgData->m_pwszName);
    sprintf(pDbgInfo, "%s", ctmp);

    if(0 != pDbgData->m_lTextAdd){
        slen = strlen(pDbgInfo);
        sprintf(&pDbgInfo[slen], " 0x%x", pDbgData->m_lTextAdd);
    }

    if(0 != pDbgData->m_lDataAdd){
        slen = strlen(pDbgInfo);
        sprintf(&pDbgInfo[slen], " -s .data 0x%x", pDbgData->m_lDataAdd);
    }

    if(0 != pDbgData->m_lBssAdd){
        slen = strlen(pDbgInfo);
        sprintf(&pDbgInfo[slen], " -s .bss 0x%x", pDbgData->m_lBssAdd);
    }

    strcat(pDbgInfo, ";");
}

static int SendBuffer(int fd, char op, void *buf, int iSendSize)
{
    int iWriteSize;
    char *p;

    iWriteSize = 0;

    p = (char *)buf;

    char cmd = '^';
    if(0 > write(fd, &cmd, 1)){
        PERROR("Error: write failed! \
            file:%s. line:%d. \n",
            __FILE__, __LINE__);
        return 1;
    }

    if(0 > write(fd, &op, 1)){
        PERROR("Error: write failed! \
            file:%s. line:%d. \n",
            __FILE__, __LINE__);
        return 1;
    }

    while(iWriteSize < iSendSize){
        iWriteSize = write(fd, p, iSendSize);
        if(-1 == iWriteSize){
            if(errno == EINTR){
                continue;
            }
            PERROR("Error: write failed! \
                file:%s. line:%d. \n",
                __FILE__, __LINE__);
            break;
        }
        iSendSize -= iWriteSize;
        p += iWriteSize;
    }

    cmd = '^';
    if(0 > write(fd, &cmd, 1)){
        PERROR("Error: write failed! \
            file:%s. line:%d. \n",
            __FILE__, __LINE__);
        return 1;
    }

    return 0;

}

//FORMAT:^FILENAME 0x.TEXTADD -s .data 0x.DATAADD -s .bss 0x.BSSADD^;
EXTERN_C int SendModlueDbgInfo(int fd, CModule * pModule)
{
    DbgData dData;

    char pDbgInfo[AURA_MAX_PATH];
    int iDbgInfoSize;

    GetDbgData(pModule, &dData);

    SetDbgInfo(pDbgInfo, &dData);

    iDbgInfoSize = strlen(pDbgInfo) + 1;
    printf("AddDllSymbolToList Module DbgInfo:%s.\n", pDbgInfo);
	//The cmd 's' in another file dll_symbol.c
    SendBuffer(fd, 's', pDbgInfo, iDbgInfoSize);

    return 0;
}

EXTERN_C int SendCreateThreadDbgInfo(int fd, int tid)
{
    printf("SendCreateThreadDbgInfo tid:%d.\n", tid);
    //The cmd 't' in another file dll_symbol.c
    SendBuffer(fd, 't', &tid, sizeof(int));

    return 0;
}

EXTERN_C void SetDebugFlag(int fd)
{
    //printf("g_iDbgFlag_fd :%d\n", fd);
    g_iDbgFlag_fd = fd;
}
